package org.gdstash.db;

import org.gdstash.ui.GDStashFrame;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

public class ItemCriteriaCombination implements Cloneable {
    private String itemClass;
    private String armorClass;
    private String artifactClass;
    private String itemRarity;
    private boolean useArmorClass;
    private boolean useArtifactClass;
    private boolean useItemRarity;
    private boolean useSlots;
    private int levelMin;
    private int levelMax;
    private int cunningMax;
    private int physiqueMax;
    private int spiritMax;
    private boolean noEnemyOnly;
    private SelectionCriteria criteria;

    private ItemCriteriaCombination() {
        this.itemClass = null;
        this.armorClass = null;
        this.artifactClass = null;
        this.itemRarity = null;
        this.useArmorClass = false;
        this.useArtifactClass = false;
        this.useItemRarity = false;
        this.useSlots = false;
        this.levelMin = -1;
        this.levelMax = -1;
        this.cunningMax = -1;
        this.physiqueMax = -1;
        this.spiritMax = -1;
        this.noEnemyOnly = true;
        this.criteria = null;
    }

    private ItemCriteriaCombination(final ItemCriteriaCombination combo) {
        this.itemClass = combo.itemClass;
        this.armorClass = combo.armorClass;
        this.artifactClass = combo.artifactClass;
        this.itemRarity = combo.itemRarity;
        this.useArmorClass = combo.useArmorClass;
        this.useArtifactClass = combo.useArtifactClass;
        this.useItemRarity = combo.useItemRarity;
        this.useSlots = combo.useSlots;
        this.levelMin = combo.levelMin;
        this.levelMax = combo.levelMax;
        this.cunningMax = combo.cunningMax;
        this.physiqueMax = combo.physiqueMax;
        this.spiritMax = combo.spiritMax;
        this.noEnemyOnly = combo.noEnemyOnly;
        this.criteria = combo.criteria;
    }

    public ItemCriteriaCombination(final SelectionCriteria criteria) {
        this();
        this.levelMin = criteria.levelMin;
        this.levelMax = criteria.levelMax;
        this.cunningMax = criteria.cunningMax;
        this.physiqueMax = criteria.physiqueMax;
        this.spiritMax = criteria.spiritMax;
        this.noEnemyOnly = criteria.noEnemyOnly;
        this.criteria = criteria;
    }

    public ItemCriteriaCombination clone() {
        final ItemCriteriaCombination combo = new ItemCriteriaCombination(this);
        return combo;
    }

    public String getItemClass() {
        return this.itemClass;
    }

    public String getArmorClass() {
        return this.armorClass;
    }

    public String getArtifactClass() {
        return this.artifactClass;
    }

    public String getItemRarity() {
        return this.itemRarity;
    }

    public boolean usesArmorClass() {
        return this.useArmorClass;
    }

    public boolean usesArtifactClass() {
        return this.useArtifactClass;
    }

    public boolean usesItemRarity() {
        return this.useItemRarity;
    }

    public boolean usesSlots() {
        return this.useSlots;
    }

    public int getMinLevel() {
        return this.levelMin;
    }

    public int getMaxLevel() {
        return this.levelMax;
    }

    public int getMaxCunning() {
        return this.cunningMax;
    }

    public int getMaxPhysique() {
        return this.physiqueMax;
    }

    public int getMaxSpirit() {
        return this.spiritMax;
    }

    public boolean isNoEnemyOnly() {
        return this.noEnemyOnly;
    }

    private void init() {
        this.useArmorClass = false;
        if (!this.criteria.armorClass.isEmpty() && ItemClass.isArmor(this.itemClass)) {
            this.useArmorClass = true;
        }
        this.useArtifactClass = false;
        if (!this.criteria.artifactClass.isEmpty() && ItemClass.isArtifact(this.itemClass)) {
            this.useArtifactClass = true;
        }
        this.useItemRarity = false;
        if (!this.criteria.itemRarity.isEmpty() && ItemClass.hasRarity(this.itemClass)) {
            this.useItemRarity = true;
        }
        this.useSlots = false;
        if (ItemClass.hasSlots(this.itemClass)) {
            this.useSlots = true;
        }
    }

    public void setItemClass(final String itemClass) {
        if (itemClass == null) {
            this.itemClass = null;
            return;
        }
        if (itemClass.isEmpty()) {
            this.itemClass = null;
            return;
        }
        this.itemClass = itemClass;
        this.init();
    }

    public void setArmorClass(final String armorClass) {
        if (armorClass == null) {
            this.armorClass = null;
            return;
        }
        if (armorClass.isEmpty()) {
            this.armorClass = null;
            return;
        }
        this.armorClass = armorClass;
    }

    public void setArtifactClass(final String artifactClass) {
        if (artifactClass == null) {
            this.artifactClass = null;
            return;
        }
        if (artifactClass.isEmpty()) {
            this.artifactClass = null;
            return;
        }
        this.artifactClass = artifactClass;
    }

    public void setItemRarity(final String itemRarity) {
        if (itemRarity == null) {
            this.itemRarity = null;
            return;
        }
        if (itemRarity.isEmpty()) {
            this.itemRarity = null;
            return;
        }
        this.itemRarity = itemRarity;
    }

    public String determineItemParameters() {
        String param = this.itemClass;
        if (this.useItemRarity) {
            param = param + ", " + this.itemRarity;
        }
        if (this.useArmorClass) {
            param = param + ", " + this.armorClass;
        }
        if (this.useArtifactClass) {
            param = param + ", " + this.artifactClass;
        }
        if (this.levelMin != -1) {
            param = param + ", " + Integer.toString(this.levelMin);
        }
        if (this.levelMax != -1) {
            param = param + ", " + Integer.toString(this.levelMax);
        }
        if (this.cunningMax != -1) {
            param = param + ", " + Integer.toString(this.cunningMax);
        }
        if (this.physiqueMax != -1) {
            param = param + ", " + Integer.toString(this.physiqueMax);
        }
        if (this.spiritMax != -1) {
            param = param + ", " + Integer.toString(this.spiritMax);
        }
        return param;
    }

    public String determineItemStatement() {
        String command = "SELECT * FROM GD_ITEM WHERE ITEM_CLASS = ?";
        if (this.useItemRarity) {
            command += " AND RARITY = ?";
        }
        if (this.useArmorClass) {
            command += " AND ARMOR_CLASS = ?";
        }
        if (this.useArtifactClass) {
            command += " AND ARTIFACT_CLASS = ?";
        }
        if (this.levelMin != -1) {
            command += " AND REQ_LEVEL >= ?";
        }
        if (this.levelMax != -1) {
            command += " AND REQ_LEVEL <= ?";
        }
        if (this.cunningMax != -1) {
            command += " AND REQ_DEX <= ?";
        }
        if (this.physiqueMax != -1) {
            command += " AND REQ_STR <= ?";
        }
        if (this.spiritMax != -1) {
            command += " AND REQ_INT <= ?";
        }
        if (this.noEnemyOnly) {
            command += " AND ENEMY_ONLY = ?";
        }
        command += this.determineSlotConditions(null);
        return command;
    }

    public String determineItemIDStatement() {
        String command = "SELECT ITEM_ID FROM GD_ITEM WHERE ITEM_CLASS = ?";
        if (this.useItemRarity) {
            command += " AND RARITY = ?";
        }
        if (this.useArmorClass) {
            command += " AND ARMOR_CLASS = ?";
        }
        if (this.useArtifactClass) {
            command += " AND ARTIFACT_CLASS = ?";
        }
        if (this.levelMin != -1) {
            command += " AND REQ_LEVEL >= ?";
        }
        if (this.levelMax != -1) {
            command += " AND REQ_LEVEL <= ?";
        }
        if (this.cunningMax != -1) {
            command += " AND REQ_DEX <= ?";
        }
        if (this.physiqueMax != -1) {
            command += " AND REQ_STR <= ?";
        }
        if (this.spiritMax != -1) {
            command += " AND REQ_INT <= ?";
        }
        if (this.noEnemyOnly) {
            command += " AND ENEMY_ONLY = ?";
        }
        command += this.determineSlotConditions(null);
        return command;
    }

    public String determineStashIDItemStatement(final boolean isHardcore) {
        String command = "SELECT S.STASH_ID FROM STASH_ITEM_V10 S, GD_ITEM I WHERE S.ITEM_ID = I.ITEM_ID AND I.ITEM_CLASS = ?";
        if (!GDStashFrame.iniConfig.sectRestrict.transferSCHC) {
            if (isHardcore) {
                command += " AND S.HARDCORE = true";
            } else {
                command += " AND S.HARDCORE = false";
            }
        }
        if (this.useItemRarity) {
            command += " AND I.RARITY = ?";
        }
        if (this.useArmorClass) {
            command += " AND I.ARMOR_CLASS = ?";
        }
        if (this.useArtifactClass) {
            command += " AND I.ARTIFACT_CLASS = ?";
        }
        if (this.levelMin != -1) {
            command += " AND I.REQ_LEVEL >= ?";
        }
        if (this.levelMax != -1) {
            command += " AND I.REQ_LEVEL <= ?";
        }
        if (this.cunningMax != -1) {
            command += " AND I.REQ_DEX <= ?";
        }
        if (this.physiqueMax != -1) {
            command += " AND I.REQ_STR <= ?";
        }
        if (this.spiritMax != -1) {
            command += " AND I.REQ_INT <= ?";
        }
        if (this.noEnemyOnly) {
            command += " AND I.ENEMY_ONLY = ?";
        }
        command += this.determineSlotConditions("I.");
        return command;
    }

    public int fillItemStatement(final PreparedStatement ps) throws SQLException {
        ps.clearParameters();
        int nextPos = 1;
        ps.setString(nextPos, this.itemClass);
        ++nextPos;
        if (this.useItemRarity) {
            ps.setString(nextPos, this.itemRarity);
            ++nextPos;
        }
        if (this.useArmorClass) {
            ps.setString(nextPos, this.armorClass);
            ++nextPos;
        }
        if (this.useArtifactClass) {
            ps.setString(nextPos, this.artifactClass);
            ++nextPos;
        }
        if (this.levelMin != -1) {
            ps.setInt(nextPos, this.levelMin);
            ++nextPos;
        }
        if (this.levelMax != -1) {
            ps.setInt(nextPos, this.levelMax);
            ++nextPos;
        }
        if (this.cunningMax != -1) {
            ps.setInt(nextPos, this.cunningMax);
            ++nextPos;
        }
        if (this.physiqueMax != -1) {
            ps.setInt(nextPos, this.physiqueMax);
            ++nextPos;
        }
        if (this.spiritMax != -1) {
            ps.setInt(nextPos, this.spiritMax);
            ++nextPos;
        }
        if (this.noEnemyOnly) {
            ps.setBoolean(nextPos, false);
            ++nextPos;
        }
        return nextPos;
    }

    public String determineSlotConditions(final String prefix) {
        String command = "";
        if (!this.useSlots) {
            return command;
        }
        boolean firstSlot = true;
        if (this.criteria.slotAxe1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_AXE_1H = true";
            } else {
                command = command + prefix + "SLOT_AXE_1H = true";
            }
        }
        if (this.criteria.slotAxe2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_AXE_2H = true";
            } else {
                command = command + prefix + "SLOT_AXE_2H = true";
            }
        }
        if (this.criteria.slotDagger1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_DAGGER_1H = true";
            } else {
                command = command + prefix + "SLOT_DAGGER_1H = true";
            }
        }
        if (this.criteria.slotMace1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_MACE_1H = true";
            } else {
                command = command + prefix + "SLOT_MACE_1H = true";
            }
        }
        if (this.criteria.slotMace2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_MACE_2H = true";
            } else {
                command = command + prefix + "SLOT_MACE_2H = true";
            }
        }
        if (this.criteria.slotScepter1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SCEPTER_1H = true";
            } else {
                command = command + prefix + "SLOT_SCEPTER_1H = true";
            }
        }
        if (this.criteria.slotSpear1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SPEAR_1H = true";
            } else {
                command = command + prefix + "SLOT_SPEAR_1H = true";
            }
        }
        if (this.criteria.slotSpear2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SPEAR_2H = true";
            } else {
                command = command + prefix + "SLOT_SPEAR_2H = true";
            }
        }
        if (this.criteria.slotStaff2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_STAFF_2H = true";
            } else {
                command = command + prefix + "SLOT_STAFF_2H = true";
            }
        }
        if (this.criteria.slotSword1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SWORD_1H = true";
            } else {
                command = command + prefix + "SLOT_SWORD_1H = true";
            }
        }
        if (this.criteria.slotSword2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SWORD_2H = true";
            } else {
                command = command + prefix + "SLOT_SWORD_2H = true";
            }
        }
        if (this.criteria.slotRanged1H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_RANGED_1H = true";
            } else {
                command = command + prefix + "SLOT_RANGED_1H = true";
            }
        }
        if (this.criteria.slotRanged2H) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_RANGED_2H = true";
            } else {
                command = command + prefix + "SLOT_RANGED_2H = true";
            }
        }
        if (this.criteria.slotShield) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SHIELD = true";
            } else {
                command = command + prefix + "SLOT_SHIELD = true";
            }
        }
        if (this.criteria.slotOffhand) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_OFFHAND = true";
            } else {
                command = command + prefix + "SLOT_OFFHAND = true";
            }
        }
        if (this.criteria.slotAmulet) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_AMULET = true";
            } else {
                command = command + prefix + "SLOT_AMULET = true";
            }
        }
        if (this.criteria.slotBelt) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_BELT = true";
            } else {
                command = command + prefix + "SLOT_BELT = true";
            }
        }
        if (this.criteria.slotMedal) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_MEDAL = true";
            } else {
                command = command + prefix + "SLOT_MEDAL = true";
            }
        }
        if (this.criteria.slotRing) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_RING = true";
            } else {
                command = command + prefix + "SLOT_RING = true";
            }
        }
        if (this.criteria.slotHead) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_HEAD = true";
            } else {
                command = command + prefix + "SLOT_HEAD = true";
            }
        }
        if (this.criteria.slotShoulders) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_SHOULDERS = true";
            } else {
                command = command + prefix + "SLOT_SHOULDERS = true";
            }
        }
        if (this.criteria.slotChest) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_CHEST = true";
            } else {
                command = command + prefix + "SLOT_CHEST = true";
            }
        }
        if (this.criteria.slotHands) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_HANDS = true";
            } else {
                command = command + prefix + "SLOT_HANDS = true";
            }
        }
        if (this.criteria.slotLegs) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_LEGS = true";
            } else {
                command = command + prefix + "SLOT_LEGS = true";
            }
        }
        if (this.criteria.slotFeet) {
            if (firstSlot) {
                firstSlot = false;
                command += " AND ( ";
            } else {
                command += " OR ";
            }
            if (prefix == null) {
                command += "SLOT_FEET = true";
            } else {
                command = command + prefix + "SLOT_FEET = true";
            }
        }
        if (!firstSlot) {
            command += " )";
        }
        return command;
    }

    public List<ItemCriteriaCombination> createItemCombinations() {
        final List<ItemCriteriaCombination> list = new LinkedList<ItemCriteriaCombination>();
        final ItemCriteriaCombination combo = new ItemCriteriaCombination(this);
        boolean found = false;
        if (combo.usesItemRarity()) {
            for (final String itemRarity : this.criteria.itemRarity) {
                combo.setItemRarity(itemRarity);
                if (combo.usesArmorClass()) {
                    for (final String armorClass : this.criteria.armorClass) {
                        combo.setArmorClass(armorClass);
                        list.add(combo.clone());
                    }
                    found = true;
                }
                if (!found) {
                    list.add(combo.clone());
                }
            }
        } else {
            if (combo.usesArmorClass()) {
                for (final String armorClass2 : this.criteria.armorClass) {
                    combo.setArmorClass(armorClass2);
                    list.add(combo.clone());
                }
                found = true;
            }
            if (combo.usesArtifactClass()) {
                for (final String artifactClass : this.criteria.artifactClass) {
                    combo.setArtifactClass(artifactClass);
                    list.add(combo.clone());
                }
                found = true;
            }
            if (!found) {
                list.add(combo.clone());
            }
        }
        return list;
    }

    public List<ItemCriteriaCombination> createAffixCombinations() {
        final List<ItemCriteriaCombination> list = new LinkedList<ItemCriteriaCombination>();
        final ItemCriteriaCombination combo = new ItemCriteriaCombination(this);
        if (combo.usesItemRarity()) {
            for (final String itemRarity : this.criteria.itemRarity) {
                combo.setItemRarity(itemRarity);
                list.add(combo.clone());
            }
        } else {
            list.add(combo.clone());
        }
        return list;
    }
}
